/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.lifxue.jqda.ui.autofield;

import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author lifxue
 */
public class AutoCompletionField extends JTextField implements DocumentListener, MouseListener, ListSelectionListener, ActionListener, KeyListener {

    private static Log logger = LogFactory.getLog(AutoCompletionField.class);
    private static int DEFAULT_PREFERRED_HEIGHT = 200;
    private ListPopup popup;
    private int preferredHeight = DEFAULT_PREFERRED_HEIGHT;
    private CompletionFilter filter;

    public void setFilter(CompletionFilter f) {
        filter = f;
    }

    public AutoCompletionField() {
        popup = new ListPopup();
        getDocument().addDocumentListener(this);
        addMouseListener(this);
        popup.addListSelectionListener(this);
        addActionListener(this);
        addKeyListener(this);
    }

    public void setPopupPreferredHeight(int h) {
        preferredHeight = h;
    }

    private boolean isListChange(ArrayList array) {
        if (array.size() != popup.getItemCount()) {
            return true;
        }
        for (int i = 0; i < array.size(); i++) {
            if (!array.get(i).equals(popup.getItem(i))) {
                return true;
            }
        }
        return false;
    }

    private void textChanged() {
        if ("".equals(this.getText())) {
            popup.setVisible(false);
        } else {
            if (!popup.isVisible()) {
                showPopup();
                //requestFocus();
                requestFocusInWindow();
            }
            if (filter != null) {
                ArrayList array = filter.filter(getText());
                changeList(array);
            }

        }

    }

    private void showPopup() {
        popup.setPopupSize(getWidth(), preferredHeight);
        popup.show(this, 0, getHeight() - 1);

    }

    private void changeList(ArrayList array) {
        if (array.isEmpty()) {
            if (popup.isVisible()) {
                popup.setVisible(false);
            }
        } else {
            if (!popup.isVisible()) {
                showPopup();
            }
        }
        if (isListChange(array) && !array.isEmpty()) {
            popup.setList(array);
            popup.setSelectedIndex(0);
        }
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        //logger.debug("insertUpdate");
        textChanged();
    }

    @Override
    public void removeUpdate(DocumentEvent e) {
        //logger.debug("removeUpdate");
        textChanged();
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
        //logger.debug("changedUpdate");
        textChanged();
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        //logger.debug("mouseClicked");
        if (e.getClickCount() > 1 && !popup.isVisible()) {
            textChanged();
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    /**
     * JList的鼠标单击监听
     * 在下拉列表上鼠标单击一列数据，激活此监听
     * @param e
     */
    @Override
    public void valueChanged(ListSelectionEvent e) {
        JList list = (JList) e.getSource();
        String text = list.getSelectedValue().toString();
        //logger.debug(text);
        setText(text);
        popup.setVisible(false);
    }

    /**
     * 回车键监听
     *
     * @param e
     */
    @Override
    public void actionPerformed(ActionEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            if (popup.isVisible()) {
                if (!popup.isSelected()) {
                    popup.setSelectedIndex(0);
                } else {
                    popup.setSelectedIndex(popup.getSelectedIndex() + 1);
                }
            }
        } else if (e.getKeyCode() == KeyEvent.VK_UP) {
            if (popup.isVisible()) {
                if (!popup.isSelected()) {
                    popup.setLastOneSelected();
                } else {
                    popup.setSelectedIndex(popup.getSelectedIndex() - 1);
                }
            }
        } else if (e.getKeyCode() == KeyEvent.VK_PAGE_DOWN) {
            if (popup.isVisible()) {
                if (!popup.isSelected()) {
                    popup.setSelectedIndex(0);
                } else {
                    popup.setSelectedIndex(popup.getSelectedIndex() + 5);
                }
            }
        } else if (e.getKeyCode() == KeyEvent.VK_PAGE_UP) {
            if (popup.isVisible()) {
                if (!popup.isSelected()) {
                    popup.setLastOneSelected();
                } else {
                    popup.setSelectedIndex(popup.getSelectedIndex() - 5);
                }
            }
        } else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
            if (popup.isVisible()) {
                Object o = popup.getSelectedValue();
                if (o != null) {
                    setText(o.toString());
                    //logger.debug(o.toString());
                }
                popup.setVisible(false);
            }
            this.selectAll();
            this.requestFocus();

        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
}
